# coding=utf-8

import asyncio
import time
from typing import Dict, List, Optional

from obespoir.server.frame.frame_server import FrameServer, FrameConfig
from ...base.global_object import GlobalObject
from ...share.espoir_log import log_record
from ..user_manager import User
from ...share.singleton import Singleton
from ...share.espoir_log import global_log as logger


class FrameManager(object, metaclass=Singleton):

    def __init__(self) -> None:
        self._server_info: Dict[str, FrameServer] = {}
        self._frame_no: int = 0

    async def run(self) -> None:
        cur_time: int = int(time.time() * 1000)
        default_config: FrameConfig = GlobalObject().default_frame_config
        cur_frame_no = int(cur_time / default_config.frame_interval)
        cur_frame_time = cur_frame_no * default_config.frame_interval
        while True:
            for _, serv in self._server_info.items():
                await serv.run()

            cur_time = int(time.time() * 1000)
            next_frame_time = cur_frame_time + default_config.frame_interval
            need_wait_time = max(next_frame_time - cur_time, 0)
            # logger.info("frame run", cur_frame_no=cur_frame_no,
            #             next_wait_time=need_wait_time)
            await asyncio.sleep(need_wait_time / 1000.0)

            cur_frame_no += 1
            cur_frame_time = next_frame_time

    @log_record
    def create_server(self, game_id: str, user_list: List[User],
                      frame_config: Optional[FrameConfig] = None) \
            -> Optional[FrameServer]:
        if game_id in self._server_info:
            return None
        if frame_config is None:
            frame_config = GlobalObject().default_frame_config
        serv = FrameServer(game_id, frame_config)
        serv.add_users(user_list)
        self._server_info[game_id] = serv
        logger.info("success", game_id=game_id, user_list=user_list)
        return serv

    @log_record
    def delete_server(self, game_id: str) -> None:
        if game_id in self._server_info:
            self._server_info[game_id].clear()
            del self._server_info[game_id]

    @log_record
    def add_op(self, game_id: str, op: Dict) -> None:
        if game_id not in self._server_info:
            return
        self._server_info[game_id].add_op(op)
